package net.towee.client.com.repo.view;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.towee.client.com.repo.presenter.RepositoryTreeNodePresenter.Display;
import net.towee.client.i18n.ToweeConstants;
import net.towee.client.resources.ClientResource;
import net.towee.client.widgets.ExtFlowPanel;
import net.towee.client.widgets.LoadingBar;
import net.towee.client.widgets.SpanPanel;
import net.towee.model.repo.DocumentType;
import net.towee.model.repo.NodeData;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.logical.shared.HasOpenHandlers;
import com.google.gwt.event.logical.shared.HasValueChangeHandlers;
import com.google.gwt.event.logical.shared.OpenEvent;
import com.google.gwt.event.logical.shared.OpenHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.inject.Inject;

public class RepositoryTreeNodeView extends ExtFlowPanel implements Display, HasOpenHandlers<NodeData>,
		HasValueChangeHandlers<NodeData> {
	private final ToweeConstants constants;
	private final ClientResource resource;

	private final FlowPanel pathSelector;
	private final FlowPanel catalogsContainer;
	private final Map<DocumentType, FlowPanel> docsContainers;
	private final Map<String, Widget> nodes;
	private final LoadingBar loading;

	private SpanPanel nomessage = null;

	@Inject
	public RepositoryTreeNodeView(ToweeConstants constants, ClientResource resource) {
		this.constants = constants;
		this.resource = resource;
		this.loading = new LoadingBar(resource);

		docsContainers = new HashMap<DocumentType, FlowPanel>();
		nodes = new HashMap<String, Widget>();

		catalogsContainer = new FlowPanel();
		pathSelector = new FlowPanel();

		createPathSelector();
		createCatalogsContainer();
		createDocuemtnsContainers();
	}

	@Override
	public void noNodesMessage() {
		nomessage = new SpanPanel(constants.repoNoNodes());
		nomessage.setStyleName(resource.css().repoNoNodesMessage());
		add(nomessage);
	}

	private void createPathSelector() {
		add(pathSelector);
		pathSelector.setStyleName(resource.css().repoNodeSelectorContainer());
	}

	@Override
	public HasWidgets getPathSelectorContainer() {
		return pathSelector;
	}

	private void createDocuemtnsContainers() {
		for (DocumentType type : DocumentType.values()) {
			FlowPanel container = new FlowPanel();
			FlowPanel cont = new FlowPanel();
			cont.setStyleName(resource.css().repoNodesContainer());
			container.add(createCategoryLabel(constants.getString("DOCTYPE_" + type + "S"), cont));
			container.add(cont);
			add(container);

			container.setVisible(false);
			cont.setVisible(false);
			docsContainers.put(type, cont);
		}
	}

	private void createCatalogsContainer() {
		FlowPanel container = new FlowPanel();
		catalogsContainer.setStyleName(resource.css().repoNodesContainer());
		container.add(createCategoryLabel(constants.catalolgs(), catalogsContainer));
		container.add(catalogsContainer);
		container.setVisible(false);
		catalogsContainer.setVisible(false);
		add(container);
	}

	private Widget createCategoryLabel(String name, final Widget container) {
		ExtFlowPanel label = new ExtFlowPanel();
		ExtFlowPanel nameContainer = new ExtFlowPanel(name);
		FlowPanel line = new FlowPanel();

		label.setStyleName(resource.css().repoCategoryLabel());
		nameContainer.setStyleName(resource.css().repoCategoryLabelName());
		line.setStyleName(resource.css().repoCategoryLabelLine());

		label.add(nameContainer);
		label.add(line);
		label.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				if (container.isVisible())
					container.setVisible(false);
				else
					container.setVisible(true);
			}
		});

		return label;
	}

	private HasClickHandlers createNodeLabel(final NodeData node, Image img, boolean canRemove,
			boolean canEdit) {
		// Create label
		final ExtFlowPanel cat = new ExtFlowPanel();
		cat.setLayoutData(node);
		cat.getElement().setAttribute("node", "catalog");
		cat.add(img);
		cat.add(new Label(node.getName()));

		// Create remove link if neede
		if (canRemove) {
			Button btn = new Button();
			cat.add(btn);
			btn.addClickHandler(new ClickHandler() {
				@Override
				public void onClick(ClickEvent event) {
					event.stopPropagation();

					FlowPanel content = new FlowPanel();
					final PopupPanel shure = new PopupPanel();
					shure.setStyleName(resource.css().repoDocumentExplPopup());
					content.getElement().getStyle().setProperty("textAlign", "center");
					content.getElement().getStyle().setProperty("fontSize", "1.3em");
					shure.setWidget(content);

					content.add(new Label("Вы точно хотите удалить?"));

					Button yes = new Button("Да", new ClickHandler() {
						@Override
						public void onClick(ClickEvent event) {
							ValueChangeEvent.fire(RepositoryTreeNodeView.this, node);
							shure.hide();
						}
					});
					content.add(yes);

					Button no = new Button("Нет", new ClickHandler() {
						@Override
						public void onClick(ClickEvent event) {
							shure.hide();
						}
					});
					content.add(no);

					yes.setStyleName(resource.css().lobbyNextStepButton());
					no.setStyleName(resource.css().lobbyCloseButton());

					shure.setPopupPosition(cat.getAbsoluteLeft() + 60, cat.getAbsoluteTop() - 45);
					shure.setAutoHideEnabled(true);
					shure.setGlassEnabled(false);
					shure.show();
				}
			});
		}

		return cat;
	}

	private HasClickHandlers createCatalog(NodeData node, boolean canRemove, boolean canEdit) {
		return createNodeLabel(node, new Image(resource.folder()), canRemove, canEdit);
	}

	private HasClickHandlers createDocument(NodeData node, DocumentType type, boolean canRemove,
			boolean canEdit) {
		// Create img for document
		Image img = null;
		switch (type) {
		case DISCUSSION:
			img = new Image(resource.discussion());
			break;
		default:
			img = new Image(resource.document());
			break;
		}

		return createNodeLabel(node, img, canRemove, canEdit);
	}

	@Override
	public void showNode(final NodeData node, boolean canRemove, boolean canEdit) {
		// Remove no message if it showed
		if (nomessage != null) {
			nomessage.removeFromParent();
			nomessage = null;
		}

		// Remove old node if exists
		removeNode(node);

		// For container
		FlowPanel container = null;
		HasClickHandlers catWidget = null;

		if (node.toTreeNode() != null) {
			catWidget = createCatalog(node, canRemove, canEdit);
			catalogsContainer.add((Widget) catWidget);
			container = catalogsContainer;
		} else {
			// Get general type
			DocumentType type = node.toDocumentNode().getDocumentIdentity().getDocumentTypes()
					.getTypesList().get(0);

			// Create item
			catWidget = createDocument(node, type, canRemove, canEdit);

			// Add to container of given doc types
			container = docsContainers.get(type);
			container.add((Widget) catWidget);
		}

		// Put to cache
		nodes.put(node.getId(), (Widget) catWidget);

		// Show container
		container.getParent().setVisible(true);
		container.setVisible(true);

		// Add handler
		catWidget.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				OpenEvent.fire(RepositoryTreeNodeView.this, node);
			}
		});
	}

	@Override
	public void removeNode(NodeData node) {
		if (nodes.containsKey(node.getId())) {
			Widget label = nodes.get(node.getId());

			if (((FlowPanel) label.getParent()).getWidgetCount() == 1)
				label.getParent().getParent().setVisible(false);

			label.removeFromParent();
			nodes.remove(node.getId());
		}
	}

	@Override
	public List<NodeData> getSelectedNodes() {
		return new ArrayList<NodeData>();
	}

	@Override
	public HasOpenHandlers<NodeData> getOpenNodeEvents() {
		return this;
	}

	@Override
	public HasValueChangeHandlers<NodeData> getDeleteEvents() {
		return this;
	}

	@Override
	public HandlerRegistration addOpenHandler(OpenHandler<NodeData> handler) {
		return addHandler(handler, OpenEvent.getType());
	}

	@Override
	public HandlerRegistration addValueChangeHandler(ValueChangeHandler<NodeData> handler) {
		return addHandler(handler, ValueChangeEvent.getType());
	}

	@Override
	public void startLoadingNodes() {
		loading.toggle();
	}

	@Override
	public void endLoadingNodes() {
		loading.toggle();
	}
}
